package com.fowo.api.syncLingxingApi.service;


import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fowo.api.datainterface.constants.DataTypeKind;
import com.fowo.api.datainterface.constants.RequestMethodKind;
import com.fowo.api.datainterface.entity.DatainterfaceAuthority;
import com.fowo.api.datainterface.service.impl.DatainterfaceAuthorityServiceImpl;
import com.fowo.api.datainterface.util.Common;
import com.fowo.api.datainterface.util.RedisUtil;
import com.fowo.api.datainterface.util.RestUtilLingXing;
import com.fowo.api.entity.Product;
import com.fowo.api.service.impl.ProductServiceImpl;
import com.fowo.api.syncLingxingApi.entity.TmpSyncLingxingToAuxBase;
import com.fowo.api.syncLingxingApi.entity.TmpSyncLingxingToSpuBase;
import com.fowo.api.sys.entity.SysFile;
import com.fowo.api.sys.service.FileService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.IOUtils;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public abstract class SyncBaseService {
    @Resource
    protected ProductServiceImpl productService;
    @Resource
    protected RestUtilLingXing restUtilLingXing;
    @Resource
    protected RedisUtil redisUtil;
    @Resource
    protected FileService fileService;
    protected String catchKey = "Lingxing:Spu:List";

    protected String lxApiToken = null;
    protected String lxApiAppId = null;
    protected String lxApiAppSecret = null;
    protected String lxApiTokenUrl = null;
    protected String lxApiUrl = null;
    protected String data_version = null;

    private int RETRY_TIMES = 10;
    private String LX_API_URL_KEY = null;

    protected SyncBaseService(String urlKey, Integer retryTime) {
        this.LX_API_URL_KEY = urlKey;
        this.RETRY_TIMES = Convert.toInt(retryTime, 10);
    }

    protected boolean initData() {
        Assert.isTrue(ObjectUtil.isNotEmpty(LX_API_URL_KEY), "LX_API_URL_KEY为空");
        DatainterfaceAuthority entityAuthority = SpringUtil.getBean(DatainterfaceAuthorityServiceImpl.class).getOne(Wrappers.<DatainterfaceAuthority>lambdaQuery().eq(DatainterfaceAuthority::getAppCode, DataTypeKind.Lingxing), false);
        String appId = Common.getAuthoritySimpleFactory(entityAuthority, "appId");
        String appSecret = Common.getAuthoritySimpleFactory(entityAuthority, "appSecret");
        String tokenUrl = Common.getAuthoritySimpleFactory(entityAuthority, "tokenUrl");
        String apiUrl = Common.getAuthoritySimpleFactory(entityAuthority, LX_API_URL_KEY);
        Assert.isTrue(ObjectUtil.isAllNotEmpty(appId, appSecret), "请配置授权格式,例: {\"appId\":\"\",\"appSecret\":\"\"}");
        this.lxApiAppId = appId;
        this.lxApiAppSecret = appSecret;
        this.lxApiTokenUrl = tokenUrl;
        this.lxApiUrl = apiUrl;
        this.lxApiToken = getToken();
        this.data_version =  DateUtil.format(DateUtil.date(), DatePattern.PURE_DATETIME_MS_PATTERN);
        return (this.lxApiToken != null && this.lxApiToken != "");
    }

    protected String getToken() {
        final Map<String, Object> REQUEST_PARAMS = Map.of("appId", this.lxApiAppId, "appSecret", this.lxApiAppSecret);

        for (int i = 0; i != RETRY_TIMES; ++i) {
            Object lingXingRequest = SpringUtil.getBean(RestUtilLingXing.class).lingXingRequest("1", RequestMethodKind.Post.getValue(), REQUEST_PARAMS,
                    this.lxApiTokenUrl, null, null);
            JSONObject jsonObject = null;
            try {
                jsonObject = (JSONObject) lingXingRequest;
            } catch (ClassCastException ex) {
                log.warn("连接" + this.lxApiToken + "异常");
                continue;
            }
            // 应该还有个返回的错误码不等于0
            if (!"200".equals(jsonObject.get("code"))) {
                log.warn("尝试" + String.valueOf(i + 1) + "/" + String.valueOf(RETRY_TIMES) +
                        "，获取token失败: " + jsonObject.toJSONString());
                continue;
            } else {
                //取得access-token
                return ((JSONObject) jsonObject.get("data")).get("access_token").toString();
            }
        }
        // MARK: 输出日志 获取日志失败
        log.error("重试" + String.valueOf(RETRY_TIMES) + "次后，获取token失败！");
        return null;
    }

    protected JSONObject tryRequestLingxingApi(Map<String, Object> requestBody, String apiUrl) {
        JSONObject resultJson = null;
        Map<String, Object> headers = new HashMap<>();
        for (int i = 0; i < RETRY_TIMES; ++i) {
            Map<String, Object> requestParams = new HashMap<>();
            requestParams.put("access_token", this.lxApiToken);
            requestParams.put("app_key", this.lxApiAppId);
            requestParams.put("timestamp", System.currentTimeMillis() / 1000);
            resultJson = (JSONObject) restUtilLingXing.lingXingRequestBatch(
                    "2",
                    RequestMethodKind.Post.getValue(),
                    requestParams,
                    apiUrl,
                    headers,
                    requestBody
            );

            Integer code = resultJson.getInteger("code");
            if (code == 0) {
                break;
            } else if (code == 500) {
                log.error("拉取数据失败。Data=" + requestBody.toString() + "。Url=" + apiUrl);
                break;
            } else if (i == RETRY_TIMES - 1) {
                log.warn("拉取数据重试多次失败. Data=" + requestBody.toString() + "。Url=" + apiUrl);
            } else {
                log.warn("请求失败5秒后重试。" + resultJson.toJSONString());
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    log.error("系统程序异常", e);
                }
                if (code == 3001008 || code == 2001005) {
                    this.lxApiToken = getToken();
                    // MARK: log.output
                    log.warn(resultJson.toJSONString());
                }
            }
        }

        return resultJson;
    }


    protected <T extends TmpSyncLingxingToSpuBase> List<T> compareNewOrOldDataSpu(List<T> newObject, List<Product> oldObject) {
        List<T> results = new ArrayList<>();
        while (!newObject.isEmpty()) {
            T newOne = newObject.get(0);
            newObject.remove(newOne);

            Product oldOne = null;
            for (Product product : oldObject) {
                if (newOne.getSpu().equals(product.getSpu())) {
                    oldOne = product;
                    oldObject.remove(product);
                    break;
                }
            }

            // 旧数据没有匹配，则为新数据
            if (oldOne == null) {
                newOne.set_version(this.data_version);
                newOne.set_flag(2);
                results.add(newOne);
                continue;
            }
            newOne.set_version(this.data_version);
            newOne.set_flag(1);
            results.add(newOne);
        }
        return results;
    }


    protected <T extends TmpSyncLingxingToAuxBase> List<T> compareNewOrOldDataAux(List<T> newObject, List<Product> oldObject) {
        List<T> results = new ArrayList<>();
        while (!newObject.isEmpty()) {
            T newOne = newObject.get(0);
            newObject.remove(newOne);

            Product oldOne = null;
            for (Product product : oldObject) {
                if (newOne.getSku().equals(product.getSku())) {
                    oldOne = product;
                    oldObject.remove(product);
                    break;
                }
            }
            // 旧数据没有匹配，则为新数据
            if (oldOne == null) {
                newOne.set_version(this.data_version);
                newOne.set_flag(2);
                results.add(newOne);
                continue;
            }
            newOne.set_version(this.data_version);
            newOne.set_flag(1);
            results.add(newOne);
        }
        return results;
    }


    protected List<SysFile> uploadImage(String picUrl) {
        List<SysFile> fileList = new ArrayList<>();
        if (picUrl != null && !picUrl.isEmpty()) {
            MultipartFile multipartFile = null;
            try {
                multipartFile = onlineAddressTransferFile(picUrl);
                if (multipartFile != null) {
                    SysFile file = fileService.upload(multipartFile, null);
                    fileList.add(file);
                }
            } catch (Exception e) {
                log.error("上传失败：" + picUrl, e);
            }
        }
        return fileList;
    }

    protected MultipartFile onlineAddressTransferFile(String strUrl) throws IOException {
        InputStream stream = getInputStreamByUrl(strUrl);
        if (!ObjectUtils.isEmpty(stream)) {
            return new MockMultipartFile("网络图片", FileUtil.getName(strUrl), "image/jpeg", stream);
        } else {
            log.error("获取网络文件失败 > " + strUrl);
        }
        return null;
    }

    protected InputStream getInputStreamByUrl(String strUrl) {
        HttpURLConnection conn = null;
        try {
            if (StrUtil.isNotBlank(strUrl)) {
                URL url = new URL(strUrl);
                conn = (HttpURLConnection) url.openConnection();
                conn.setRequestMethod("GET");
                conn.setConnectTimeout(20 * 1000);

                final ByteArrayOutputStream output = new ByteArrayOutputStream();
                InputStream inputStream = conn.getInputStream();
                IOUtils.copy(inputStream, output);
                return new ByteArrayInputStream(output.toByteArray());
            }
        } catch (FileNotFoundException e) {
            log.error("FileNotFoundException: " + strUrl);
        } catch (Exception e) {
            log.error("获取图片时失败，未知异常: " + strUrl, e);
        } finally {
            try {
                if (conn != null) {
                    conn.disconnect();
                }
            } catch (Exception e) {
                log.error("获取图片时，连接失败: " + strUrl, e);
            }
        }
        return null;
    }


}
